/*
        TUIO processing demo - part of the reacTIVision project
        http://mtg.upf.es/reactable

        Copyright (c) 2006 Martin Kaltenbrunner <mkalten@iua.upf.es>

        Permission is hereby granted, free of charge, to any person obtaining
        a copy of this software and associated documentation files
        (the "Software"), to deal in the Software without restriction,
        including without limitation the rights to use, copy, modify, merge,
        publish, distribute, sublicense, and/or sell copies of the Software,
        and to permit persons to whom the Software is furnished to do so,
        subject to the following conditions:

        The above copyright notice and this permission notice shall be
        included in all copies or substantial portions of the Software.

        Any person wishing to distribute modifications to the Software is
        requested to send the modifications to the original developer so that
        they can be incorporated into the canonical version.

        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
        EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
        MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
        IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
        ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
        CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
        WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import tuio.*;

TuiObjectList objectList;
TuiCursorList cursorList;
TuioClient client;

void setup()
{
  size(640,480);
  noStroke();
  fill(0);
  noLoop();
  redraw();
  objectList = new TuiObjectList();
  cursorList = new TuiCursorList();
  client  = new TuioClient(this);
}

void draw()
{
  background(255);
  cursorList.draw();
  objectList.draw();
}

// called after each message bundle
void refresh() { redraw(); }

// called when an object is added to the scene
void addTuiObject(Integer s_id, Integer f_id) {
  objectList.activate(s_id,f_id);
  //System.out.println("add object "+f_id+" ("+s_id+")");
}

// called when an object is removed from the scene
void removeTuiObject(Integer s_id,Integer f_id ) {
  objectList.deactivate(s_id);
  //System.out.println("remove object "+f_id+" ("+s_id+")");
}

// called when an object is moved
void updateTuiObject (Integer s_id, Integer f_id, Float xpos, Float ypos, Float angle) {
  objectList.update(s_id,(int)(640*xpos.floatValue()),(int)(480*ypos.floatValue()),angle.floatValue());
  //System.out.println("update object "+f_id+" ("+s_id+")");
}

// called when a cursor appears the scene
void addTuiCursor(Integer s_id) {
  //System.out.println("add cursor "+s_id);
  cursorList.add(s_id);
  redraw();
}

// called when a cursor is removed from the scene
void removeTuiCursor(Integer s_id) {
  //System.out.println("remove cursor "+s_id);
  cursorList.remove(s_id);
  redraw();
}

// called when a cursor is moved
void updateTuiCursor (Integer s_id, Float xpos, Float ypos) {
  //System.out.println("update cursor "+s_id+" "+xpos+" "+ypos);
  cursorList.update(s_id,(int)(640*xpos.floatValue()),(int)(480*ypos.floatValue()));
  redraw();
}
//--------------------------------------------------------------------------------------------------
//helper classes

class TuiObjectList {

  java.util.Hashtable objectList;

  TuiObjectList() {
    textFont(createFont("Sans", 12));
    objectList = new Hashtable();
  }

  void draw() { 
    Enumeration e = objectList.elements();
    while (e.hasMoreElements()) {
      ((TuiObject)e.nextElement()).draw();
    }
  }
  
  TuiObject getObject(Integer s_id) {
    return (TuiObject)objectList.get(s_id);
  }
  
  void activate(Integer s_id, Integer f_id) { 
    TuiObject nobj = new TuiObject(s_id.intValue(), f_id.intValue());
    objectList.put(s_id,nobj);
  }
  
  void deactivate(Integer s_id) {
    objectList.remove(s_id);
  }
  void update(Integer s_id, int x, int y, float a) {
    TuiObject tobj = (TuiObject)objectList.get(s_id);
    if (tobj!=null) tobj.update(x,y,a);
  }
}

class TuiObject {
  int session_id, fiducial_id;
  int xpos, ypos;
  float angle;

  TuiObject(int s_id,int f_id) {
    session_id  = s_id;
    fiducial_id = f_id; 
    xpos = 0; 
    ypos = 0; 
    angle = 0.0f;
    rectMode(CENTER);
  }

  void update(int x, int y, float a) {
    xpos=x;
    ypos=y;
    angle=a;
  }

  void draw() {
   stroke(0);
   fill(0);
   pushMatrix();
   translate(xpos,ypos);
   rotate(angle);
   rect(0,0,50,50);
   popMatrix();
   fill(255);
   text(""+fiducial_id, xpos, ypos);
  }
}
  class TuiCursorList {

  java.util.Hashtable cursorList;

  TuiCursorList() {
    cursorList = new Hashtable();
  }

  void draw() {
    stroke(0,0,255);
    Enumeration e = cursorList.elements();
    while (e.hasMoreElements()) {
      Vector pointList = (Vector)e.nextElement();
      
      if (pointList.size()>0) {
        Point start_point = (Point)pointList.elementAt(0);
        for (int i=0;i<pointList.size();i++) {
           Point end_point = (Point)pointList.elementAt(i);
           line(start_point.x,start_point.y,end_point.x,end_point.y);
           start_point = end_point;
        } 
      }
    }
  }
  
  void add(Integer s_id) { 
    Vector pointList = new Vector();
    cursorList.put(s_id,pointList);
  }
  
  void remove(Integer s_id) {
    cursorList.remove(s_id);
  }
  
  void update(Integer s_id, int xpos, int ypos) {
    Vector pointList = (Vector)cursorList.get(s_id);
    if (pointList!=null) pointList.addElement(new Point(xpos,ypos));
  }
}
